package pl.koziolekweb.loggerservice;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils.FieldCallback;

public class LogServicePostProcessor implements BeanPostProcessor {

	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {

		try {
			ReflectionUtils.doWithFields(bean.getClass(), new FieldCallback() {
				public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
					LogService logServiceAnnotation = getLogServiceAnnotation(field);
					if (logServiceAnnotation != null) {
						try {
							Class<LoggerFactoryAdapter<Object>> loggerFactoryAdapterClass = null;
							if (logServiceAnnotation.value().equals(Void.class)) {
								Class<LoggerFactoryAdapter> loggerFactoryAdapterClassLoader = LoggerFactoryAdapter.class;
								loggerFactoryAdapterClass = (Class<LoggerFactoryAdapter<Object>>) Class
										.forName(logServiceAnnotation.value().getCanonicalName());
							} else {
								loggerFactoryAdapterClass = (Class<LoggerFactoryAdapter<Object>>) logServiceAnnotation
										.value();
							}
							LoggerFactoryAdapter<Object> newInstance = loggerFactoryAdapterClass.newInstance();
							setLogger(bean, field, newInstance.getLogger(bean.getClass()));
						} catch (InstantiationException e) {
							e.printStackTrace();
						} catch (ClassNotFoundException e) {
							e.printStackTrace();
						}

					}
				}

				private LogService getLogServiceAnnotation(Field field) {
					LogService logServiceAnnotation = field.getAnnotation(LogService.class);
					if (logServiceAnnotation == null) {
						Annotation[] annotations = field.getAnnotations();
						for (int i = 0; i < annotations.length; ++i) {
							Annotation a = annotations[i];
							Class<? extends Annotation> annotationType = a.annotationType();
							logServiceAnnotation = annotationType.getAnnotation(LogService.class);
							if (logServiceAnnotation != null)
								break;

						}
					}
					return logServiceAnnotation;
				}
			});
		} catch (Exception e) {
			throw new BeansException("", e) {
			};
		}
		return bean;
	}

	private void setLogger(final Object bean, Field field, Object log) throws IllegalAccessException {
		boolean orginalAccessFlag = field.isAccessible();
		field.setAccessible(true);
		field.set(bean, log);
		field.setAccessible(orginalAccessFlag);
	}

}
